#include <deque>
#include <functional>
#include <iostream>
#include <mutex>
#include <thread>

std::mutex g_mtx1{};
std::mutex g_mtx2{};
int g_nSharedData{};

/**
 * @brief 互斥锁的使用
 */
void Lock()
{
    std::thread t1{
        []()
        {
            while (true)
            {
                g_mtx1.lock();
                g_nSharedData++; // 全局变量不需要捕获
                std::cout << "Current thread is:" << std::this_thread::get_id() << std::endl;
                std::cout << "Shared data is:" << g_nSharedData << std::endl;
                g_mtx1.unlock();
                std::this_thread::sleep_for(std::chrono::microseconds(10));
            }
        }
    };

    std::thread t2{
        []()
        {
            while (true)
            {
                g_mtx2.lock();
                g_nSharedData++; // 全局变量不需要捕获
                std::cout << "Current thread is:" << std::this_thread::get_id() << std::endl;
                std::cout << "Shared data is:" << g_nSharedData << std::endl;
                g_mtx2.unlock();
                std::this_thread::sleep_for(std::chrono::microseconds(10));
            }
        }
    };

    t1.join();
    t2.join();
}

void GuardLock()
{
    std::thread t3{
        []()
        {
            while (true)
            {
                {
                    std::lock_guard<std::mutex> lock{g_mtx1};
                    g_nSharedData++;
                }
                std::cout << "Current thread is:" << std::this_thread::get_id() << std::endl;
                std::cout << "Shared data is:" << g_nSharedData << std::endl;

                std::this_thread::sleep_for(std::chrono::microseconds(10));
            }
        }
    };
}

/**
 * @brief 线程危险的栈
 * @tparam T 数据类型
 * @tparam Container 底层容器
 */
template <typename T, template<typename ,typename > class Container = std::deque>
class ThreadDangerStack
{
public:
    ThreadDangerStack() = default;

    ThreadDangerStack(const ThreadDangerStack& other)
        : _data(other._data)
    {
    };

    ThreadDangerStack(ThreadDangerStack&& other) noexcept
        : _data(std::move(other._data))
    {
    };

    ThreadDangerStack(std::initializer_list<T> init)
        : _data(init.begin(), init.end())
    {
    };

    template <typename Iterator>
    ThreadDangerStack(Iterator first, Iterator last)
        : _data(first, last)
    {
    };

    ~ThreadDangerStack() = default;

public:
    T& top()
    {
        std::lock_guard lock{_mux};
        if (_data.empty())
        {
            throw std::out_of_range("Stack is empty");
        }

        return _data.back();
    }

    const T& top() const
    {
        std::lock_guard lock{_mux};
        if (_data.empty())
        {
            throw std::out_of_range("Stack is empty");
        }

        return _data.back();
    }

    bool empty() const
    {
        std::lock_guard lock{_mux};
        return _data.empty();
    }

    auto size() const
    {
        std::lock_guard lock{_mux};
        return _data.size();
    }

    void push(const T& value)
    {
        std::lock_guard lock{_mux};
        _data.push_back(value);
    }

    void pop()
    {
        std::lock_guard lock{_mux};
        if (_data.empty())
        {
            throw std::out_of_range("Stack is empty");
        }
        _data.pop_back();
    }

private:
    Container<T, std::allocator<T>> _data{}; // 默认底层容器为deque
    mutable std::mutex _mux{}; // 可修改
};

/**
 * @brief ThreadDangerStack存在经典的竞胎条件
 */
void DangerStackOperator()
{
    ThreadDangerStack<int> nVar{1};
    std::jthread t1{
        [&nVar]()
        {
            if (!nVar.empty())
            {
                std::this_thread::sleep_for(std::chrono::seconds(1));
                nVar.pop();
            }
        }
    };
    std::jthread t2{
        [&nVar]()
        {
            if (!nVar.empty())
            {
                std::this_thread::sleep_for(std::chrono::seconds(1));
                nVar.pop();
            }
        }
    };
}

void DeadLock()
{
    std::thread t1{
        []()
        {
            while (true)
            {
                std::cout << "Thread 1: Try to get g_mtx1" << std::endl;
                g_mtx1.lock();
                std::cout << "Thread 1: Have got g_mtx1" << std::endl;

                std::this_thread::sleep_for(std::chrono::microseconds(10));

                std::cout << "Thread 1: Try to get g_mtx2" << std::endl;
                g_mtx2.lock();
                std::cout << "Thread 1: Have got g_mtx2" << std::endl;

                g_nSharedData++; // 全局变量不需要捕获
                std::cout << "Thread 1 finished operation:" << g_nSharedData << std::endl;

                g_mtx2.unlock(); // 就近先解锁
                g_mtx1.unlock();

                std::this_thread::sleep_for(std::chrono::microseconds(10));
            }
        }
    };

    std::thread t2{
        []()
        {
            while (true)
            {
                std::cout << "Thread 2: Try to get g_mtx2" << std::endl;
                g_mtx2.lock();
                std::cout << "Thread 2: Have got g_mtx2" << std::endl;

                std::this_thread::sleep_for(std::chrono::microseconds(10));

                std::cout << "Thread 2: Try to get g_mtx2" << std::endl;
                g_mtx1.lock();
                std::cout << "Thread 2: Have got g_mtx2" << std::endl;

                g_nSharedData++; // 全局变量不需要捕获
                std::cout << "Thread 2 finished operation:" << g_nSharedData << std::endl;

                g_mtx1.unlock();
                g_mtx2.unlock(); // 就近先解锁

                std::this_thread::sleep_for(std::chrono::microseconds(10));
            }
        }
    };

    t1.join();
    t2.join();
}

/**
 * @brief 将加锁和解锁封装为独立函数
 */
void DeadLockSolution1()
{
    auto Lock1 = []()
    {

    };


    std::thread t1{
        []()
        {
            while (true)
            {
                std::cout << "Thread 1: Try to get g_mtx1" << std::endl;
                g_mtx1.lock();
                std::cout << "Thread 1: Have got g_mtx1" << std::endl;

                std::this_thread::sleep_for(std::chrono::microseconds(10));

                std::cout << "Thread 1: Try to get g_mtx2" << std::endl;
                g_mtx2.lock();
                std::cout << "Thread 1: Have got g_mtx2" << std::endl;

                g_nSharedData++; // 全局变量不需要捕获
                std::cout << "Thread 1 finished operation:" << g_nSharedData << std::endl;

                g_mtx2.unlock(); // 就近先解锁
                g_mtx1.unlock();

                std::this_thread::sleep_for(std::chrono::microseconds(10));
            }
        }
    };

    std::thread t2{
        []()
        {
            while (true)
            {
                std::cout << "Thread 2: Try to get g_mtx2" << std::endl;
                g_mtx2.lock();
                std::cout << "Thread 2: Have got g_mtx2" << std::endl;

                std::this_thread::sleep_for(std::chrono::microseconds(10));

                std::cout << "Thread 2: Try to get g_mtx2" << std::endl;
                g_mtx1.lock();
                std::cout << "Thread 2: Have got g_mtx2" << std::endl;

                g_nSharedData++; // 全局变量不需要捕获
                std::cout << "Thread 2 finished operation:" << g_nSharedData << std::endl;

                g_mtx1.unlock();
                g_mtx2.unlock(); // 就近先解锁

                std::this_thread::sleep_for(std::chrono::microseconds(10));
            }
        }
    };

    t1.join();
    t2.join();
}

int main()
{
    // Lock();
    // DangerStackOperator();
    // DeadLock();

    return 0;
}
